(() => {

	/**
	* @typedef { Object } Config
	* @property { HTMLElement } element
	* @property { string } title_template
	* @property { () => HTMLInputElement[] } other_inputs
	* @property { (value: number)=>{ x: number; y: number; } } math_calc
	* @property { boolean } math_calc_input_x
	* @property { number } x_axis_range_value
	* @property { number } y_axis_range_value
	* @property { number } draw_count_value
	*/

	/** @type { (config: Config) => void; } */
	const Draw = function (config) {

		// 初始化函数
		/** @type { (min: number, max: number, split: number, value: number, unit: number) => number[]; } */
		const SplitNumber = window.Global_SplitNumber;
		const math_calc = config.math_calc;

		// 初始化页面
		config.element.innerHTML = `<div id="title_box">${config.title_template}</div>
<br />

<canvas id="canvas"></canvas>
<br />
<br />

x轴范围：<input type="text" id="x_axis_range_input" value="${config.x_axis_range_value}" /><br />
y轴范围：<input type="text" id="y_axis_range_input" value="${config.y_axis_range_value}" /><br />
绘制点数：<input type="text" id="draw_count_input" value="${config.draw_count_value}" /><br />`;

		// 初始化元素
		/** @type { HTMLCanvasElement } */
		const canvas = document.getElementById("canvas");
		const context = canvas.getContext("2d");

		/** @type { HTMLInputElement } */ const x_axis_range_input = document.getElementById("x_axis_range_input");
		/** @type { HTMLInputElement } */ const y_axis_range_input = document.getElementById("y_axis_range_input");
		/** @type { HTMLInputElement } */ const draw_count_input = document.getElementById("draw_count_input");

		// 初始化事件处理
		/** @param e { WheelEvent & { wheelDelta: number; } }  */
		const input_onmousewheel = function (e) {
			const isDown = e.wheelDelta < 0;
			const change_space = isDown ? -1 : 1;

			const pressCtrl = e.ctrlKey;
			const pressShift = e.shiftKey;
			const change_unit = pressCtrl && pressShift
				? 1000
				: pressShift
					? 100
					: pressCtrl
						? 10
						: 1;

			e.preventDefault();

			const change_value = change_unit * change_space;

			const old_value = parseFloat(this.value);
			const old_value_number = Number.isInteger(old_value) ? old_value : 0;

			this.value = (old_value_number + change_value).toString();

			CanvasDraw();
		};

		let canvasWieth = 0;
		let canvasHeight = 0;

		/**
		 * 画板_大小发生变化
		*/
		const CanvasResize = function () {
			context.imageSmoothingEnabled = false;
			canvasWieth = canvas.width = canvas.offsetWidth;
			canvasHeight = canvas.height = canvas.offsetHeight;

			CanvasDraw();
		};

		/**
		 * 画板_绘制
		*/
		const CanvasDraw = function () {
			if (canvasWieth <= 0 || canvasHeight <= 0) {
				return;
			}

			// 绘制背景
			context.save();
			context.fillStyle = "#FFFFFF";
			context.fillRect(0, 0, canvasWieth, canvasHeight);
			context.restore();

			const size = Math.min(canvasWieth, canvasHeight);
			const center = size / 2;

			// 绘制轴线
			context.save();
			context.strokeStyle = "#D5D5D5";
			context.lineWidth = 2;
			context.beginPath();
			context.moveTo(0, center);
			context.lineTo(size, center);
			context.stroke();
			context.beginPath();
			context.moveTo(center, 0);
			context.lineTo(center, size);
			context.stroke();
			context.restore();

			// 绘制0
			context.save();
			context.font = `${16}px 微软雅黑`;
			context.fillStyle = "#888";
			context.textBaseline = "top";
			context.textAlign = "right";
			context.fillText("0", center - 5, center + 5);
			context.restore();

			// 计算点区间
			const count = Math.abs(parseInt(draw_count_input.value));
			const oneSize = size / count;
			const xRange = Math.abs(parseInt(x_axis_range_input.value));
			const yRange = Math.abs(parseInt(y_axis_range_input.value));
			const xHref = xRange / 2;
			const yHref = yRange / 2;
			const xStart = -xHref;
			const yStart = -yHref;

			const oneYSpace = yRange / count;
			const oneXSpace = xRange / count;

			/** @param x { number } */ const getX = (x) => (x + xHref) / oneXSpace * oneSize;
			/** @param y { number } */ const getY = (y) => (yHref - y) / oneYSpace * oneSize;

			// 绘制x轴标尺
			context.save();
			context.fillStyle = "#888";
			context.strokeStyle = "#888";

			const x_axis_ruler = SplitNumber(xStart, xHref, 20, 1, 10);
			for (const x of x_axis_ruler) {
				if (x === 0) {
					continue;
				}
				const top = center;
				const left = getX(x);

				context.save();

				context.beginPath();
				context.moveTo(left, top);
				context.lineTo(left, top - 5);
				context.stroke();

				context.textAlign = "center";
				context.fillText(x.toString(), left, top - 7);

				context.restore();
			}

			context.restore();

			// 绘制y轴标尺
			const y_axis_ruler = SplitNumber(yStart, yHref, 20, 1, 10);
			for (const y of y_axis_ruler) {
				if (y === 0) {
					continue;
				}
				const top = getY(y);
				const left = center;

				context.save();

				context.beginPath();
				context.moveTo(left, top);
				context.lineTo(left + 5, top);
				context.stroke();

				context.textAlign = "left";
				context.textBaseline = "middle";
				context.fillText(y.toString(), left + 7, top);

				context.restore();
			}

			context.restore();

			// 绘制点位置
			context.save();
			context.fillStyle = "#0072FD";

			for (let i = 0; i < count; i++) {
				const { x, y } = math_calc(config.math_calc_input_x ? (xStart + oneXSpace * i) : (yStart + oneYSpace * i));

				if (x < xStart || x > - xStart) {
					continue;
				}

				const top = getY(y);
				const left = getX(x);

				context.save();
				context.beginPath();
				context.arc(left, top, 1, 0, 2 * Math.PI);
				context.fill();
				context.restore();
			}

			context.restore();
		};

		// 绑定事件
		const resizeObserver = new ResizeObserver(() => CanvasResize());
		resizeObserver.observe(canvas);

		[x_axis_range_input, y_axis_range_input, draw_count_input, ...config.other_inputs()].forEach(element => {
			element.oninput = CanvasResize;
			element.onmousewheel = input_onmousewheel;
		});

	};
	window.Global_Draw = Draw;
})();
